package visualizer.client.widgets.algoPanel;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Node;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.Style;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.*;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import visualizer.client.event.AlgorithmChangeHandler;
import visualizer.client.utils.AlgorithmType;
import visualizer.client.utils.ScaleInfo;

/**
 * User: DDovzhenko
 * Date: 29.12.13
 * Time: 13:29
 */
public class AlgorithmPanelView extends Composite implements AlgorithmPanelPresenter.Display {
    public static final String SELECTED = "selected";
    public static final String HOVER = "hover";
    public static final String SHOW = "show";

    @UiField
    DivElement algoPanel;
    @UiField
    SpanElement openButton;
    @UiField
    SpanElement balanceGroup;
    @UiField
    SpanElement bstGroup;
    @UiField
    SpanElement rBstGroup;
    @UiField
    SpanElement sBstGroup;
    @UiField
    SpanElement rbBstGroup;
    @UiField
    DivElement balanceAlgorithms;
    @UiField
    DivElement bstAlgorithms;
    @UiField
    DivElement rBstAlgorithms;
    @UiField
    DivElement sBstAlgorithms;
    @UiField
    DivElement rbBstAlgorithms;
    @UiField
    DivElement addAlgoBST;
    @UiField
    DivElement removeAlgoBST;
    @UiField
    DivElement findAlgoBST;
    @UiField
    DivElement balanceAlgoWithVine;
    @UiField
    DivElement addAlgoRBST;
    @UiField
    DivElement removeAlgoRBST;
    @UiField
    DivElement findAlgoRBST;
    @UiField
    DivElement addAlgoSBST;
    @UiField
    DivElement removeAlgoSBST;
    @UiField
    DivElement findAlgoSBST;
    @UiField
    DivElement addAlgoRBBST;
    @UiField
    DivElement removeAlgoRBBST;
    @UiField
    DivElement findAlgoRBBST;
    @UiField
    DivElement selectedAlgorithm;
    @UiField
    DivElement selectedAlgoFullName;

    private AlgorithmChangeHandler changeListener;
    private boolean isShow = false;

    public AlgorithmPanelView() {
        initWidget(ourUiBinder.createAndBindUi(this));
        initListeners();
    }

    private void initListeners() {
        createClickListener(addAlgoBST, AlgorithmType.BST_ADDING);
        createClickListener(removeAlgoBST, AlgorithmType.BST_REMOVING);
        createClickListener(findAlgoBST, AlgorithmType.BST_SEARCHING);
        createClickListener(balanceAlgoWithVine, AlgorithmType.BALANCE_WITH_VINE);
        createClickListener(addAlgoRBST, AlgorithmType.RANDOMIZE_BST_ADDING);
        createClickListener(removeAlgoRBST, AlgorithmType.RANDOMIZE_BST_REMOVING);
        createClickListener(findAlgoRBST, AlgorithmType.RANDOMIZE_BST_SEARCHING);
        createClickListener(addAlgoSBST, AlgorithmType.SPLAY_BST_ADDING);
        createClickListener(removeAlgoSBST, AlgorithmType.SPLAY_BST_REMOVING);
        createClickListener(findAlgoSBST, AlgorithmType.SPLAY_BST_SEARCHING);
        createClickListener(addAlgoRBBST, AlgorithmType.RED_BLACK_BST_ADDING);
        createClickListener(removeAlgoRBBST, AlgorithmType.RED_BLACK_BST_REMOVING);
        createClickListener(findAlgoRBBST, AlgorithmType.RED_BLACK_BST_SEARCHING);
        DOM.sinkEvents(openButton.<Element>cast(), Event.ONCLICK);
        DOM.setEventListener(openButton.<Element>cast(), new EventListener() {
            @Override
            public void onBrowserEvent(Event event) {
                if (isShow) {
                    algoPanel.removeClassName(SHOW);
                } else {
                    algoPanel.addClassName(SHOW);
                }
                isShow = !isShow;
            }
        });
        createOnHoverListener(balanceGroup, balanceAlgorithms);
        createOnHoverListener(bstGroup, bstAlgorithms);
        createOnHoverListener(rBstGroup, rBstAlgorithms);
        createOnHoverListener(sBstGroup, sBstAlgorithms);
        createOnHoverListener(rbBstGroup, rbBstAlgorithms);
        Event.addNativePreviewHandler(new Event.NativePreviewHandler() {
            @Override
            public void onPreviewNativeEvent(Event.NativePreviewEvent event) {
                if (!isShow) {
                    return;
                }
                switch (event.getTypeInt()) {
                    case Event.ONCLICK:
                    case Event.ONDBLCLICK:
                    case Event.ONMOUSEDOWN:
                        if (algoPanel.isOrHasChild(event.getNativeEvent().getEventTarget().<Node>cast())) {
                            return;
                        }
                        algoPanel.removeClassName(SHOW);
                        isShow = false;
                    default:
                        break;
                }
            }
        });
    }

    private void createOnHoverListener(final SpanElement groupName, final DivElement group) {
        DOM.sinkEvents(groupName.<Element>cast(), Event.ONMOUSEOVER | Event.ONMOUSEOUT);
        DOM.setEventListener(groupName.<Element>cast(), new EventListener() {
            @Override
            public void onBrowserEvent(Event event) {
                if (!isShow) {
                    return;
                }
                if (event.getTypeInt() == Event.ONMOUSEOVER) {
                    groupName.getFirstChildElement().addClassName(HOVER);
                    openSubMenu(group, groupName.getOffsetTop());
                } else {
                    groupName.getFirstChildElement().removeClassName(HOVER);
                    hideSubMenu(group);
                }
            }
        });
    }

    private void openSubMenu(DivElement group, int top) {
        algoPanel.getStyle().setOverflow(Style.Overflow.VISIBLE);
        group.getStyle().setDisplay(Style.Display.BLOCK);
        group.getStyle().setTop(top, Style.Unit.PX);
    }

    private void hideSubMenu(DivElement group) {
        algoPanel.getStyle().setOverflow(Style.Overflow.HIDDEN);
        group.getStyle().setDisplay(Style.Display.NONE);
    }

    private void createClickListener(final DivElement button, final AlgorithmType algorithmType) {
        DOM.sinkEvents(button.<Element>cast(), Event.ONCLICK);
        DOM.setEventListener(button.<Element>cast(), new EventListener() {
            @Override
            public void onBrowserEvent(Event event) {
                addAlgoBST.removeClassName(SELECTED);
                removeAlgoBST.removeClassName(SELECTED);
                findAlgoBST.removeClassName(SELECTED);
                balanceAlgoWithVine.removeClassName(SELECTED);
                addAlgoRBST.removeClassName(SELECTED);
                removeAlgoRBST.removeClassName(SELECTED);
                findAlgoRBST.removeClassName(SELECTED);
                addAlgoSBST.removeClassName(SELECTED);
                removeAlgoSBST.removeClassName(SELECTED);
                findAlgoSBST.removeClassName(SELECTED);
                addAlgoRBBST.removeClassName(SELECTED);
                removeAlgoRBBST.removeClassName(SELECTED);
                findAlgoRBBST.removeClassName(SELECTED);
                button.addClassName(SELECTED);
                hideSubMenu(DivElement.as(button.getParentElement()));
                button.getParentElement().getPreviousSiblingElement().removeClassName(HOVER);
                algoPanel.removeClassName(SHOW);
                isShow = false;
                selectedAlgorithm.setInnerHTML(button.getInnerHTML());
                selectedAlgoFullName.setInnerHTML(algorithmType.getDescription());
                changeListener.onAlgoChanged(algorithmType);
            }
        });
    }

    @Override
    public void setChangeAlgorithmListener(AlgorithmChangeHandler eventListener) {
        changeListener = eventListener;
    }

    @Override
    public void onResize() {
        algoPanel.setAttribute("style", "-moz-transform: " + ScaleInfo.getInstance().getMozTransformScale());
        selectedAlgoFullName.setAttribute("style", "-moz-transform: " + ScaleInfo.getInstance().getMozTransformScale());
    }

    //------------- UI Binder --------------
    interface AlgorithmPanelUiBinder extends UiBinder<HTMLPanel, AlgorithmPanelView> { }
    private static AlgorithmPanelUiBinder ourUiBinder = GWT.create(AlgorithmPanelUiBinder.class);
}